package com.education.platform.api.service.impl;

import com.education.platform.api.config.ThreadUser;
import com.education.platform.api.constants.RedisCacheConstant;
import com.education.platform.api.service.AccountFlowService;
import com.education.platform.api.service.RelUserPaperService;
import com.education.platform.api.vo.request.BuyPaperVO;
import com.education.platform.common.enums.*;
import com.education.platform.common.exception.AssertException;
import com.education.platform.common.exception.BusinessException;
import com.education.platform.common.redis.RedisUtils;
import com.education.platform.common.util.OrderNoGenerator;
import com.education.platform.common.web.ResponseCode;
import com.education.platform.dao.*;
import com.education.platform.dao.entity.*;
import com.education.platform.dao.model.ExaminPaperModel;
import org.springframework.beans.factory.annotation.Autowired;
import com.education.platform.common.service.impl.BaseServiceImpl;
import org.springframework.stereotype.Service;
import com.education.platform.api.service.ExaminPaperService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;

import java.text.NumberFormat;
import java.util.Date;
import java.util.List;

/**
 * describe: 试卷
 *
 * @author :
 * @date: 2020-07-15 08:43:11.650
 **/
@Service
public class ExaminPaperServiceImpl extends BaseServiceImpl<ExaminPaperDao, ExaminPaperDO> implements ExaminPaperService {

    private static final Logger LOGGER = LoggerFactory.getLogger(ExaminPaperServiceImpl.class);

    @Autowired
    private ExaminPaperDao examinPaperDao;

    @Autowired
    private AccountDao accountDao;

    @Autowired
    private AccountFlowDao accountFlowDao;

    @Autowired
    private AccountFlowService accountFlowService;

    @Autowired
    private UserPointsDao userPointsDao;
    @Autowired
    private UserOrderDao userOrderDao;
    @Autowired
    private PointsFlowDao pointsFlowDao;
    @Autowired
    private RelUserPaperDao relUserPaperDao;
    @Autowired
    private RelUserPaperService relUserPaperService;

    @Autowired
    private RedisUtils redisUtils;
    private final NumberFormat nf= NumberFormat.getNumberInstance() ;
    /**
     * 获取试卷列表
     * @param userId
     * @param gradeType
     * @return
     */
    @Override
    public List<ExaminPaperModel> getPaperList(Integer userId, String gradeType) {
        return examinPaperDao.getPaperList(userId, gradeType);
    }

    /**
     * 购买试卷
     * @param buyPaperVO
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean buyExamPaper(BuyPaperVO buyPaperVO) {
        if (buyPaperVO == null) {
            throw new BusinessException("数据为空");
        }
        ExaminPaperDO paperDO = examinPaperDao.getById(buyPaperVO.getPaperId());
        if (paperDO == null) {
            throw new BusinessException("试卷不存在");
        }
       //检查是否已经购买过
        relUserPaperService.checkRel(RelTypeEnum.PAPER.getValue(),buyPaperVO.getPaperId());

        if (!paperDO.getPrice().equals(buyPaperVO.getTotalPrice())) {
            throw new BusinessException("价格不正确");
        }
        String orderNo = OrderNoGenerator.generator();
        //豆子
        if ( PriceTypeEnum.BEAN.getValue().equals(buyPaperVO.getPriceType())) {

            AccountDO account = this.checkBeans(buyPaperVO.getTotalPrice().intValue());
            //插入豆子流水记录
            accountFlowService.createAccountFlow(account, FlowBusinessTypeEnum.BUY_PAPER, FlowTypeEnum.OUT, buyPaperVO.getTotalPrice().intValue(),orderNo);
        }
        //积分
        else if (  PriceTypeEnum.POINTS.getValue().equals(buyPaperVO.getPriceType())) {
            UserPointsDO pointsDO = this.checkPoints(buyPaperVO.getTotalPrice());
            this.savePointsFlow(pointsDO, buyPaperVO.getTotalPrice());
        }
        //保存订单
        this.saveOrder(paperDO,orderNo);
        //保存关系
        this.saveUserPaper(paperDO);
        //增加购买次数
        examinPaperDao.incUsageTimes(paperDO.getId());
        return true;
    }

    /**
     * 提交试卷结果
     * @param paperId
     * @param score
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public float commitTestResult(Integer paperId, Float score) {
        RelUserPaperDO query = new RelUserPaperDO();
        query.setPaperId(paperId);
        query.setUserId(ThreadUser.getUserId());
        //类型 试卷
        query.setRelType(RelTypeEnum.PAPER.getValue());
        RelUserPaperDO relUserPaperDO = relUserPaperDao.get(query);
        if(relUserPaperDO == null){
            throw  new BusinessException("提交失败");
        }
        //数据库记录最高分
        if(relUserPaperDO.getScore()==null||relUserPaperDO.getScore()<score){
            RelUserPaperDO update = new RelUserPaperDO();
            update.setId(relUserPaperDO.getId());
            update.setScore(score);
            relUserPaperDao.updateById(update);
        }

        redisUtils.zaddStr(RedisCacheConstant.KEY_EXAM_SCORE,score,String.valueOf(ThreadUser.getUserId()));

        //今日本次考试得分占比
        Long total = redisUtils.zcard(RedisCacheConstant.KEY_EXAM_SCORE);
        Long rank = redisUtils.zrevrank(RedisCacheConstant.KEY_EXAM_SCORE,String.valueOf(ThreadUser.getUserId()));
        if(total == null || total==0){
           return 1.00f;
        }else if(rank==null){
            return 0;
        }else{
            nf.setMaximumFractionDigits(2);
           return Float.valueOf(nf.format((total-rank)/(float)total));
        }
    }

    /**
     * 保存用户试卷关系
     * @param paperDO
     */
    private void saveUserPaper(ExaminPaperDO paperDO){
        RelUserPaperDO relUserPaperDO = new RelUserPaperDO();
        relUserPaperDO.setUserId(ThreadUser.getUserId());
        relUserPaperDO.setPaperId(paperDO.getId());
        relUserPaperDO.setCreateTime(new Date());
        relUserPaperDO.setRelType(RelTypeEnum.PAPER.getValue());
        relUserPaperDO.setDeleted(false);
        relUserPaperDao.insert(relUserPaperDO);
    }

    /**
     * 保存订单
     * @param paperDO
     */
    private void saveOrder(ExaminPaperDO paperDO,String orderNo) {
        UserOrderDO userOrder = new UserOrderDO();
        userOrder.setUserId(ThreadUser.getUserId());
        userOrder.setUserName(ThreadUser.getUserName());
        userOrder.setOrderNo(orderNo);
        userOrder.setOrderStatus(OrderStatusEnum.COMPLETE.getValue());
        userOrder.setOrderStatusName(OrderStatusEnum.COMPLETE.getDes());
        userOrder.setCreateTime(new Date());
        userOrder.setOrderType(OrderTypeEnum.PAPER_ORDER.getValue());
        userOrder.setOrderTypeName(OrderTypeEnum.PAPER_ORDER.getDes());
        userOrder.setCoverImage(paperDO.getCourseImage());
        userOrder.setGoodsId(paperDO.getId());
        userOrder.setGoodsName(paperDO.getPaperName());
        userOrder.setTotalPrice(paperDO.getPrice().intValue());
        userOrder.setNumber(1);
        userOrder.setPriceType(paperDO.getPriceType());
        userOrder.setDeleted(false);
        userOrderDao.insert(userOrder);
    }

    /**
     * 保存积分变化
     * @param userPointsDO
     * @param point
     */
    private void savePointsFlow(UserPointsDO userPointsDO, float point) {
        PointsFlowDO pointsFlowDO = new PointsFlowDO();
        pointsFlowDO.setBeforeNumber(userPointsDO.getPoints() == null ? 0f : userPointsDO.getPoints());
        pointsFlowDO.setFlowType(FlowTypeEnum.OUT.getValue());
        pointsFlowDO.setCreateTime(new Date());
        pointsFlowDO.setFlowNumber(point);
        pointsFlowDO.setAfterNumber(pointsFlowDO.getBeforeNumber() - point);
        pointsFlowDO.setDeleted(false);
        pointsFlowDO.setUserId(ThreadUser.getUserId());
        //兑换试卷
        pointsFlowDO.setBusinessType(PointsOutFlowBusinessTypeEnum.BUY_PAPER.getValue());
        pointsFlowDao.insert(pointsFlowDO);
    }

    /**
     * 检查账户豆子
     *
     * @param totalPrice
     */
    private AccountDO checkBeans(int totalPrice) {
        //检查历史豆是否足够
        AccountDO accountDO = accountDao.getByUserId(ThreadUser.getUserId());
        if (accountDO == null || accountDO.getBeanNumber() == null) {
            AssertException.throwBusinessEp("账户异常");
        }
        if (accountDO.getBeanNumber() < totalPrice) {
            throw new BusinessException("账户历史豆不足！", ResponseCode.NOT_ENOUGH.getCode());
        }
        AccountDO accountUpdate = new AccountDO();
        accountUpdate.setId(accountDO.getId());
        accountUpdate.setBeanNumber(accountDO.getBeanNumber() -totalPrice);
        accountUpdate.setUpdateTime(new Date());
        accountDao.updateById(accountUpdate);
        return accountDO;
    }

    /**
     * 检查积分
     *
     * @param totalPrice
     */
    private UserPointsDO checkPoints(float totalPrice) {

        UserPointsDO query = new UserPointsDO();
        query.setUserId(ThreadUser.getUserId());
        UserPointsDO userPointsDO = userPointsDao.get(query);
        if (userPointsDO == null || userPointsDO.getPoints() == null) {
            AssertException.throwBusinessEp("账户异常");
        }
        if (userPointsDO.getPoints() < totalPrice) {
            AssertException.throwBusinessEp("积分不足！");
        }

        UserPointsDO update = new UserPointsDO();
        update.setId(userPointsDO.getId());
        update.setPoints(userPointsDO.getPoints() -totalPrice);
        update.setUpdateTime(new Date());
        userPointsDao.updateById(update);
        return userPointsDO;
    }



}
